from typing import List, Tuple, Dict
from .card import Card
import random
from itertools import combinations

def get_hand_rank(hand_type: str) -> int:
    """获取牌型等级"""
    ranks = {
        "皇家同花顺": 9,
        "同花顺": 8,
        "四条": 7,
        "葫芦": 6,
        "同花": 5,
        "顺子": 4,
        "三条": 3,
        "两对": 2,
        "一对": 1,
        "高牌": 0
    }
    return ranks[hand_type]

def get_hand_name(rank: int) -> str:
    """获取牌型名称"""
    names = {
        9: "皇家同花顺",
        8: "同花顺",
        7: "四条",
        6: "葫芦",
        5: "同花",
        4: "顺子",
        3: "三条",
        2: "两对",
        1: "一对",
        0: "高牌"
    }
    return names[rank]

class PokerHand:
    """扑克牌型类"""
    def __init__(self, hand_type: str, best_cards: List[Card]):
        self.hand_type = hand_type
        self.best_cards = best_cards
        self.rank = get_hand_rank(hand_type)
        self.values = [card.rank_value for card in best_cards]
    
    def __lt__(self, other):
        """比较两手牌的大小"""
        if self.rank != other.rank:
            return self.rank < other.rank
        
        # 如果牌型相同，按照values比较
        for self_val, other_val in zip(self.values, other.values):
            if self_val != other_val:
                return self_val < other_val
        return False
    
    def __eq__(self, other):
        """判断两手牌是否相等"""
        return self.rank == other.rank and self.values == other.values

def evaluate_five_cards(cards: List[Card]) -> Tuple[int, List[int]]:
    """评估5张牌的牌型和大小"""
    # 按点数排序
    cards = sorted(cards, key=lambda x: x.rank_value, reverse=True)
    
    # 检查同花
    is_flush = len(set(card.suit for card in cards)) == 1
    
    # 检查顺子
    values = [card.rank_value for card in cards]
    is_straight = False
    # 处理A2345的特殊情况
    if values == [12, 3, 2, 1, 0]:  # A5432
        is_straight = True
        values = [3, 2, 1, 0, -1]  # 将A视为最小
    else:
        is_straight = all(values[i] - values[i+1] == 1 for i in range(4))
    
    # 统计点数
    value_counts = {}
    for card in cards:
        value_counts[card.rank_value] = value_counts.get(card.rank_value, 0) + 1
    
    # 皇家同花顺
    if is_flush and is_straight and values[0] == 12:  # A开头
        return 9, values
    
    # 同花顺
    if is_flush and is_straight:
        return 8, values
    
    # 四条
    for value, count in value_counts.items():
        if count == 4:
            kicker = next(v for v in values if v != value)
            return 7, [value] * 4 + [kicker]
    
    # 葫芦
    has_three = False
    three_value = None
    pair_value = None
    for value, count in value_counts.items():
        if count == 3:
            has_three = True
            three_value = value
        elif count == 2:
            pair_value = value
    if has_three and pair_value is not None:
        return 6, [three_value] * 3 + [pair_value] * 2
    
    # 同花
    if is_flush:
        return 5, values
    
    # 顺子
    if is_straight:
        return 4, values
    
    # 三条
    if has_three:
        kickers = sorted([v for v in values if v != three_value], reverse=True)[:2]
        return 3, [three_value] * 3 + kickers
    
    # 两对或一对
    pairs = []
    for value, count in value_counts.items():
        if count == 2:
            pairs.append(value)
    if len(pairs) == 2:
        pairs.sort(reverse=True)
        kicker = next(v for v in values if v not in pairs)
        return 2, [pairs[0], pairs[0], pairs[1], pairs[1], kicker]
    elif len(pairs) == 1:
        pair_value = pairs[0]
        # 对于一对，我们需要按照剩余牌的大小排序
        kickers = sorted([v for v in values if v != pair_value], reverse=True)
        return 1, [pair_value, pair_value] + kickers[:3]
    
    # 高牌
    return 0, values

def evaluate_hand(hole_cards: List[Card], community_cards: List[Card]) -> PokerHand:
    """评估一手牌的大小"""
    possible_hands = list(combinations(hole_cards + community_cards, 5))
    best_hand_rank = -1
    best_hand_value = []
    best_cards = None
    
    for hand in possible_hands:
        hand_rank, hand_value = evaluate_five_cards(list(hand))
        if hand_rank > best_hand_rank or (hand_rank == best_hand_rank and hand_value > best_hand_value):
            best_hand_rank = hand_rank
            best_hand_value = hand_value
            best_cards = list(hand)
    
    hand_type = get_hand_name(best_hand_rank)
    return PokerHand(hand_type, best_cards)

def calculate_win_probability(hole_cards: List[Card], community_cards: List[Card], 
                            num_opponents: int = 1, num_simulations: int = 1000) -> float:
    """计算胜率
    
    Args:
        hole_cards: 手牌
        community_cards: 公共牌
        num_opponents: 对手数量
        num_simulations: 模拟次数
        
    Returns:
        胜率(0-1之间的浮点数)
    """
    wins = 0
    deck = []
    
    # 创建一副完整的牌
    for suit in Card.SUITS:
        for rank in Card.RANKS:
            card = Card(rank, suit)
            if card not in hole_cards and card not in community_cards:
                deck.append(card)
    
    # 进行多次模拟
    for _ in range(num_simulations):
        # 洗牌
        simulation_deck = deck.copy()
        random.shuffle(simulation_deck)
        
        # 为对手发牌
        opponent_hands = []
        for _ in range(num_opponents):
            opponent_hand = [simulation_deck.pop(), simulation_deck.pop()]
            opponent_hands.append(opponent_hand)
        
        # 补齐公共牌
        remaining_community = 5 - len(community_cards)
        simulation_community = community_cards + [simulation_deck.pop() for _ in range(remaining_community)]
        
        # 计算玩家的牌力
        player_hand = evaluate_hand(hole_cards, simulation_community)
        
        # 计算对手的牌力
        is_win = True
        for opponent_hole_cards in opponent_hands:
            opponent_hand = evaluate_hand(opponent_hole_cards, simulation_community)
            if opponent_hand > player_hand:
                is_win = False
                break
        
        if is_win:
            wins += 1
    
    return wins / num_simulations

def calculate_hand_probabilities(hole_cards: List[Card], community_cards: List[Card], 
                               num_simulations: int = 1000) -> Dict[str, float]:
    """计算各种牌型的概率
    
    Args:
        hole_cards: 手牌
        community_cards: 公共牌
        num_simulations: 模拟次数
        
    Returns:
        各种牌型的概率字典
    """
    hand_counts = {
        "皇家同花顺": 0,
        "同花顺": 0,
        "四条": 0,
        "葫芦": 0,
        "同花": 0,
        "顺子": 0,
        "三条": 0,
        "两对": 0,
        "一对": 0,
        "高牌": 0
    }
    
    deck = []
    for suit in Card.SUITS:
        for rank in Card.RANKS:
            card = Card(rank, suit)
            if card not in hole_cards and card not in community_cards:
                deck.append(card)
    
    for _ in range(num_simulations):
        simulation_deck = deck.copy()
        random.shuffle(simulation_deck)
        
        # 补齐公共牌
        remaining_community = 5 - len(community_cards)
        simulation_community = community_cards + [simulation_deck.pop() for _ in range(remaining_community)]
        
        # 评估牌型
        hand = evaluate_hand(hole_cards, simulation_community)
        hand_counts[hand.hand_type] += 1
    
    # 计算概率
    probabilities = {hand_type: count/num_simulations 
                    for hand_type, count in hand_counts.items()}
    return probabilities 